<?php

/**
 * SmartPHP framework
 *
 * @name SmartPHP framework
 * @package SmartPHP
 * @author 费尔 <admin@xuai.cn>
 * @version 3.0
 * @link http://www.SmartPHP.cn
 * @copyright SmartPHP.cn
 * @license <a href="http://www.SmartPHP.cn">SmartPHP</a>
 */

namespace Base;

/**
 * 项目
 *
 * @author 费尔 <admin@xuai.cn>
 */
class App {

    /**
     * 初始化项目
     * @access public
     */
    public static function init() {
        self::initAppDefine();
        self::initAppName();
        self::initAutoload();
        self::initConfig();
        self::initTimezone();
        self::initError();
        self::initRoute();
        self::initLang();
        self::initSession();
    }

    /**
     * 运行项目
     * @access public
     */
    public static function run() {
        self::initExec();
    }

    /**
     * 执行项目
     * @access private
     */
    public static function initExec() {
        self::action();
    }

    /**
     * 调用模块的操作方法
     * @access public
     * @param string $controller 控制器
     * @param string $action 操作
     * @param array $vars 调用参数
     */
    public static function action($controller = APP_CONTROLLER, $action = APP_ACTION, $vars = []) {
        self::invokeMethod(['\\Controller\\' . $controller, $action], $vars);
    }

    /**
     * 调用反射执行类的方法 支持参数绑定
     * @access public
     * @param string|array $method 方法
     * @param array        $vars   变量
     * @return mixed
     */
    public static function invokeMethod($method, $vars = []) {
        $reflect = is_array($method) && ($class = is_object($method[0]) ? $method[0] : new $method[0]) && isset($class) ? new \ReflectionMethod($class, $method[1]) : new \ReflectionMethod($method);
        if ($reflect->getNumberOfParameters() > 0) {
            empty($vars) && ($vars = Input::param());
            $args = [];
            foreach ($reflect->getParameters() as $param) {
                $name = $param->getName();
                $args[] = $vars[$name] ?? ($param->isDefaultValueAvailable() ? $param->getDefaultValue() : null);
            }
            $reflect->invokeArgs($class ?? null, $args);
        } else {
            $reflect->invoke($class ?? null);
        }
    }

    /**
     * 返回使用时间
     * @access public
     * @param int $start
     * @param int $end
     * @param int $dec
     */
    public static function getUsageTime($start = null, $end = null, $dec = 4) {
        return number_format((($end ?: microtime(true)) - ($start ?: START_TIME)), $dec);
    }

    /**
     * 返回用户使用内存
     * @access public
     * @param int $start
     * @param int $end
     */
    public static function getUsageMemory($start = null, $end = null) {
        return function_exists('memory_get_usage') ? number_format((($end ?: memory_get_usage()) - ($start ?: START_MEMORY)) / 1024, 2) . ' kb' : null;
    }

    /**
     * 初始化项目常用常量
     * @access private
     */
    private static function initAppDefine() {
        define('IS_CGI', (0 === strpos(PHP_SAPI, 'cgi') || false !== strpos(PHP_SAPI, 'fcgi')) ? 1 : 0 );
        define('IS_WIN', strstr(PHP_OS, 'WIN') ? 1 : 0 );
        define('IS_CLI', PHP_SAPI == 'cli' ? 1 : 0);
        //当前是否ssl (考虑CDN加密技术)
        defined('IS_SSL') or define('IS_SSL', Request::isSsl());
        //是否调试
        defined('APP_DEBUG') or define('APP_DEBUG', false);
        //是否rewrite 默认开启
        defined('URL_REWRITE') or define('URL_REWRITE', true);
        self::initDirectory();
    }

    /**
     * 初始化项目名称
     * @access private
     */
    private static function initAppName() {
        if (!defined('APP_NAME')) {
            $appName = ucfirst(strtolower(preg_match('/^[A-Za-z](\/|\.|\w)*$/', ($host = strstr($_SERVER['HTTP_HOST'], '.', true))) ? ($host !== 'www' ? $host : 'Frontend') : 'Frontend'));
            //项目名称
            define('APP_NAME', !is_dir(rtrim(PROJECT_PATH, '\\/') . DS . $appName . DS) ? 'Frontend' : $appName);
        }
        //APP目录
        defined('APP_DIRECTORY') or define('APP_DIRECTORY', rtrim(PROJECT_PATH, '\\/') . DS . ucfirst(strtolower(APP_NAME)) . DS);
    }

    /**
     * 初始化项目目录
     * @access private
     */
    private static function initDirectory() {
        //框架目录
        defined('SMARTPHP_PATH') or define('SMARTPHP_PATH', dirname(__DIR__) . DS);
        //项目目录
        defined('PROJECT_PATH') or define('PROJECT_PATH', dirname(SMARTPHP_PATH) . DS . 'App');
        //公共目录
        defined('COMMON_PATH') or define('COMMON_PATH', dirname(SMARTPHP_PATH) . DS . 'Common' . DS);
        //运行目录
        defined('RUNTIME_PATH') or define('RUNTIME_PATH', COMMON_PATH . 'Runtime' . DS);
        //缓存目录
        defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH . 'Cache' . DS);
        //临时目录
        defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH . 'Temp' . DS);
        //本地日志目录
        defined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH . 'Log' . DS);
        //网站根目录
        defined('WEB_ROOT') or define('WEB_ROOT', Request::root());
    }

    /**
     * 初始化自动加载
     * @access private
     */
    private static function initAutoload() {
        Loader::registerAutoload(function ($class) {
            $init = explode('\\', $class, 2);
            $name = $init[0];
            $class = $init[1] ?? null;
            return $class ? (Loader::import(APP_DIRECTORY . $name . DS . str_replace('\\', DS, $class) . '.class.php') || Loader::import(COMMON_PATH . $name . DS . str_replace('\\', DS, $class) . '.class.php')) : false;
        });
    }

    /**
     * 初始化项目配制
     * @access private
     */
    private static function initConfig() {
        foreach ([ SMARTPHP_PATH, COMMON_PATH, APP_DIRECTORY] as $value) {
            Config::parse(rtrim($value, '\\/') . DS . 'Config.php');
        }
    }

    /**
     * 初始化时区
     * @access public
     * @param type $timezone
     */
    public static function initTimezone($timezone = '') {
        date_default_timezone_set($timezone ?: (Config::get('timezone') ?: 'PRC'));
        mb_detect_order("UTF-8");
    }

    /**
     * 初始化项目路由器
     * @access private
     */
    private static function initRoute() {
        Route::init();
    }

    /**
     * 初始化项目语言包
     * @access private
     */
    private static function initLang() {
        //当前语言
        defined('APP_LANG') or define('APP_LANG', Config::get('langswitch') ? Lang::detect() : 'zh-cn');
        //加载框架语言
        Lang::load(SMARTPHP_PATH . 'Lang' . DS . APP_LANG . '.php');
        //如果开启了语言包加载项目语言包 支持三种格式
        if (Config::get('langswitch')) {
            foreach ([COMMON_PATH, APP_DIRECTORY] as $value) {
                Lang::load([rtrim($value, '\\/') . DS . 'Lang' . DS . APP_LANG . '.php', rtrim($value, '\\/') . DS . 'Lang' . DS . APP_LANG . DS . 'Common.php', rtrim($value, '\\/') . DS . 'Lang' . DS . APP_LANG . DS . APP_CONTROLLER . '.php']);
            }
        }
    }

    /**
     * 初始化项目Session
     * @access private
     */
    private static function initSession() {
        Config::get('session.auto') && Session::init();
    }

    /**
     * 初始化错误管理
     * @access private
     */
    private static function initError() {
        Error::init();
    }

}
